#!/usr/bin/env python3
# 模拟炮舰主炮设计游戏

import pygame
from pygame.locals import *
from sys import exit
from threading import Thread,Lock,Timer
import time,math
from random import random

#273 上
#274 下
#275 左
#276 右
#32  空格
#27  ESC

LEFT_DOWN=False
RIGHT_DOWN=False
LOCK1 = Lock()
is_alive = True
def update_screen():
    global is_alive,LOCK1
    clock1 = pygame.time.Clock()
    cycle = 0
    ship1_event = pygame.event.Event(USEREVENT, message="h")
    while is_alive:
        try:
            LOCK1.acquire()
            pygame.display.update()
            if cycle%25==0:
                pygame.event.post(ship1_event)
            cycle += 1
            LOCK1.release()
        except:
            pass
        clock1.tick(60)
        
background_image_filename = 'pics/bg2.png'
ship_image_filename = 'pics/ship1.png'
hole_img_filename = 'pics/hole1.png'
 
pygame.init()
SCREEN_SIZE = (800, 600)
screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)

background = pygame.image.load(background_image_filename).convert()
ship1 = pygame.image.load(ship_image_filename)
hole1 = pygame.image.load(hole_img_filename)

font = pygame.font.Font("hei1.ttf", 18);
font_height = font.get_linesize()

pygame.event.set_blocked(None)
pygame.event.set_allowed( [KEYDOWN,KEYUP,QUIT,USEREVENT] )

Fullscreen = True
message = ''
x = 358
y = 273
target = (x+50,y+15)
gun_aim = (386,291)
hit_dist = (0,0)
def verify_hit(effect_hit_dist,effect_wucha):
    global target,gun_aim,hit_dist
    hit_wucha = (effect_wucha[0]*random(),effect_wucha[1]*random())
    hit_dist = (gun_aim[0]-target[0]+hit_wucha[0],gun_aim[1]-target[1]+hit_wucha[1])
    if hit_dist[0]*hit_dist[0] <= effect_hit_dist[0]*effect_hit_dist[0] and \
       hit_dist[1]*hit_dist[1] <= effect_hit_dist[1]*effect_hit_dist[1]:
        return True
    else:
        return False
        
hit_count = 0
hit_report = ''
damage = 0
def hit_object( smoke_point,x,y ):
    global hit_report,hit_count,damage,LOCK1
    LOCK1.acquire()
    smoke_point.append( (x,y) )
    damage += 50 - math.sqrt(x*x)
    hit_count += 1
    if damage<100:
        hit_report='击中目标'
    else:
        hit_report='摧毁目标'
    LOCK1.release()
    
def hit_missed():
    global hit_report,LOCK1
    LOCK1.acquire()
    hit_report = '没有击中'
    LOCK1.release()
    
def damage_ship(screen,x,y):
    global LOCK1
    LOCK1.acquire()
    screen.blit( font.render( '目标已经被摧毁',\
                              False, (255, 0, 0)), (320, 200) )
    ship2 = pygame.image.load('pics/baozha1.png')
    screen.blit(ship2,(x,y))
    screen.blit( font.render( '摧毁目标', False, (255, 0, 0)), (10, font_height) )
    pygame.display.update()
    time.sleep(1)
    ship2 = pygame.image.load('pics/baozha2.png')
    screen.blit(ship2,(x,y))
    pygame.display.update()
    time.sleep(1)
    ship2 = pygame.image.load('pics/baozha3.png')
    screen.blit(ship2,(x,y))
    pygame.display.update()
    LOCK1.release()
    time.sleep(1)
    
def shot_main( distance=4000 ):
    global Fullscreen,x,y,target,gun_aim,LEFT_DOWN,RIGHT_DOWN,hit_dist,hit_report,damage,\
           font_height,background,screen,font,ship1,hole1,message,is_alive,hit_count
    is_alive=True
    t_screen= Thread(target=update_screen)
    t_screen.start()
    LEFT_DOWN=False
    RIGHT_DOWN=False
    start_time = time.time()
    damage = 0
    hit_count=0
    hit_report=''
    dy=0
    Fullscreen = False
    message = ''
    x = 358
    y = 273
    target = (x+50,y+15)
    gun_aim = (386,291)
    hit_dist = (0,0)
    smoke_point = []
    base_hit_dist = (45,12)
    effect_hit_dist = (base_hit_dist[0]*2000.0/distance,base_hit_dist[1]*2000.0/distance)
    base_wucha = (1.0,1.0)
    effect_wucha = (base_wucha[0]*distance/2000.0,base_wucha[1]*distance/2000.0,)
    hit_time = distance/1000.0
    fire_count = 0
    pygame.mixer_music.load('sound/fire.mp3')
    load_timestamp = time.time()-6
    while True:
        event = pygame.event.wait()
        d_time = time.time()-start_time
        d_y = int(math.sin( math.pi*d_time/6.0)*30)
        target = (x+50,y+d_y+15)
        if event.type == QUIT:
            is_alive = False
            break
            
        LOCK1.acquire()
        if event.type == KEYDOWN:
            if event.key == K_f and event.mod==256:
                Fullscreen = not Fullscreen
                if Fullscreen:
                    screen = pygame.display.set_mode(SCREEN_SIZE, FULLSCREEN, 32)
                else:
                    screen = pygame.display.set_mode(SCREEN_SIZE, 0, 32)
            elif event.key == 273:
                dy += 1
            elif event.key == 274:
                dy -= 1
            elif event.key == 275:
                RIGHT_DOWN = True
            elif event.key == 276:
                LEFT_DOWN = True
            elif event.key == 32:
                if time.time()-load_timestamp>5:
                    pygame.mixer_music.play()
                    if verify_hit(effect_hit_dist,effect_wucha):
                        timer1 = Timer(hit_time,hit_object,args=(smoke_point,45-random()*90,10 ))
                        timer1.start()
                    else:
                        timer2 = Timer(hit_time,hit_missed)
                        timer2.start()
                    fire_count += 1
                    load_timestamp = time.time()
            elif event.key == 27:
                is_alive = False
                LOCK1.release()
                break
        elif event.type == KEYUP:
            if event.key == 275:
                RIGHT_DOWN = False
            elif event.key == 276:
                LEFT_DOWN = False
        elif event.type == USEREVENT:
            if event.message=='h':
                x -= 1
                if LEFT_DOWN:
                    x+=3
                elif RIGHT_DOWN:
                    x-=2
        if time.time()-load_timestamp>5:
            message = '可以射击'
        else:
            message = '正在装填炮弹'
        screen.fill((255, 255, 255))
        screen.blit(background, (0,d_y))
        screen.blit(ship1,(x,y+d_y))
        screen.blit(hole1,(0,0))
        for p in smoke_point:
            show_smoke(screen,target[0]+p[0],target[1]+p[1])
        pygame.draw.circle( screen,(255,0,0),gun_aim,3 )
        screen.blit( font.render('主炮射击：%s 次'%fire_count, False, (0, 255, 0)), (10, 0) )
        screen.blit( font.render('命中次数：{0} 次，破坏率：{1:.1f}'.format(hit_count,damage), False, (0, 255, 0)), (200, 0) )
        screen.blit( font.render( hit_report, False, (255, 0, 0)), (10, font_height) )
        screen.blit( font.render( message, False, (255, 0, 0)), (300, font_height) )
        screen.blit( font.render('目标距离:%sM'%distance,\
                      False, (0, 255, 0)), (600, 0) )
        
        LOCK1.release()
        if damage>=100:
            is_alive = False
            time.sleep(1)
            damage_ship(screen,x,y+d_y)
            break
        
    
smoke1_filename = 'pics/smoke1.png'
smoke1 = pygame.image.load(smoke1_filename)
def show_smoke(screen,x,y):
    global smoke1
    screen.blit(smoke1,(x-10,y-60))
    
def ask_todo(dist):
    screen.fill((0,0,0))
    screen.blit( font.render( '下一阶段设计距离：%s，是否继续？(按 y 或 n)'%dist,\
                              False, (255, 0, 0)), (200, 200) )
    pygame.display.update()
    ret = True
    while True:
        event = pygame.event.wait()
        if event.type == KEYDOWN:
            if event.key == 121:
                ret = True
                break
            elif event.key == 110:
                ret = False
                break
    return ret
    
if __name__=='__main__':
    dist=4000
    while True:
        shot_main(dist)
        dist += 1000
        if not ask_todo(dist):
            break
